﻿using System;
using System.Collections.Generic;
using System.Text;

namespace _2022Learning.Iterator
{
    /// <summary>
    /// yield return 关键字的使用
    /// 
    /// Q：什么使用yield return && yield break；？
    /// A：因为使用二者可以很方便的实现迭代器模式；
    /// 
    /// Q：什么是迭代器模式？
    /// A:迭代器模式使得你能够获取到序列中的所有元素而不用关心是其类型是array，list，linked list或者是其他什么序列结构。这一点使得能够非常高效的构建数据处理通道(data pipeline)--即数据能够进入处理通道，进行一系列的变换，或者过滤，然后得到结果。事实上，这正是LINQ的核心模式。
    /// 
    /// Q：其他结论
    /// A：IEnumerable是对IEnumerator的封装，以支持foreach语法糖。
    /// IEnumerable<T> 和IEnumerator<T>分别继承自IEnumerable和IEnumerator以提供强类型支持(即状态机中的“现态”是强类型)
    /// yield return 是编译器对IEnumerator和IEnumerable实现的语法糖。
    /// yield return 表现是实现IEnumerator的MoveNext方法，本质是实现一个状态机。
    /// 
    /// 参考文献1：https://www.cnblogs.com/qixuejia/p/5039744.html
    /// 参考文献2：https://www.educba.com/yield-keyword-in-c-sharp/
    /// 参考文献3：https://www.cnblogs.com/zhanjindong/p/3294424.html
    /// </summary>
    public class IteratorModel
    {
        /// <summary>
        /// 生成斐波纳契数
        /// </summary>
        /// <param name="fibCount"></param>
        /// <returns></returns>
        public static IEnumerable<int> Fibs(int fibCount)
        {
            for (int i = 0, prevFib = 0, curFib = 1; i < fibCount; i++)
            {
                yield return prevFib;
                int newFib = prevFib + curFib;
                prevFib = curFib;
                curFib = newFib;
            }
        }

        public static IEnumerable<string> Foo()
        {
            yield return "One";
            yield return "Two";
            yield return "Three";
        }

        public static IEnumerable<string> Foo(bool breakEarly)
        {
            yield return "One";
            yield return "Two";
            if (breakEarly)
                yield break;

            yield return "Three";
        }

        /// <summary>
        /// yield break的用法，跳出迭代
        /// </summary>
        /// <param name="n">当斐波拉切数等于n的时候停止迭代</param>
        /// <param name="max">当循环次数等于max的时候停止</param>
        /// <returns></returns>
        public static IEnumerable<int> FindFibonacciNumber(int n, int max)
        {
            for (int a = 0, b = 0, c = 1; true; a++)
            {
                if (a > max)
                {
                    Console.Write("Searched first " + max + " Fibonacci numbers. Element " + n + " not found");
                    yield break;
                }
                if (b == n)
                {
                    yield return b;
                    yield break;
                }
                int temp = b + c;
                b = c;
                c = temp;
            }
        }
    }
}
